unit SpeechRepeat;

interface

uses
  WaveRecorders, WavePlayers, Classes;

type
  TOnEndEvent = procedure(ADuration: Integer) of object;

  TSpeechRepeat = class
  private
    FMode: Integer;
    FDelay: Integer;
    FOnEnd: TOnEndEvent;
    FRecorder: TLiveAudioRecorder;
    FPlayer: TLiveAudioPlayer;
    FStart: Int64;
    FStartPlay: Boolean;
    FPos: Integer;
    FTemp: TMemoryStream;
    procedure SetDelay(const Value: Integer);
    procedure SetMode(const Value: Integer);
    procedure SetOnEnd(const Value: TOnEndEvent);
    procedure ResponseRecorderData(Sender: TObject; const Buffer: Pointer;
      BufferSize: Cardinal; var FreeIt: Boolean);
    function LiveAudioPlayerData(Sender: TObject; const Buffer: Pointer;
      BufferSize: Cardinal; var NumLoops: Cardinal): Cardinal;
  public
    constructor Create;
    destructor  Destroy; override;
    property Mode: Integer read FMode write SetMode;
    property Delay: Integer read FDelay write SetDelay;
    property OnEnd: TOnEndEvent read FOnEnd write SetOnEnd;
    procedure Start;
    procedure Stop;
  end;

implementation

uses
  Windows, SysUtils, CommonUtils, WaveUtils;

{ TSpeechRepeat }

constructor TSpeechRepeat.Create;
begin
  FRecorder := TLiveAudioRecorder.Create(nil);
  FRecorder.PCMFormat := Mono8Bit8000Hz;
  FPlayer := TLiveAudioPlayer.Create(nil);
  FPlayer.PCMFormat := FRecorder.PCMFormat;
  FRecorder.OnData := ResponseRecorderData;
  FPlayer.OnData := LiveAudioPlayerData;
  FTemp := TMemoryStream.Create;
  FStartPlay := False;
end;

destructor TSpeechRepeat.Destroy;
begin
  FRecorder.OnData := nil;
  FPlayer.OnDataPtr := nil;
  FRecorder.Active := False;
  FPlayer.Active := False;
  FreeAndNil(FTemp);
  FreeAndNil(FRecorder);
  FreeAndNil(FPlayer);

  inherited;
end;

function TSpeechRepeat.LiveAudioPlayerData(Sender: TObject;
  const Buffer: Pointer; BufferSize: Cardinal; var NumLoops: Cardinal): Cardinal;
begin
  if FStartPlay then
  begin
    FTemp.Position := FPos;
    Result := FTemp.Read(Buffer^, BufferSize);
  end
  else
    Result := 0;
end;

procedure TSpeechRepeat.ResponseRecorderData(Sender: TObject;
  const Buffer: Pointer; BufferSize: Cardinal; var FreeIt: Boolean);
var
  nPos: Integer;
begin
  FreeIt := True;
  nPos := FTemp.Size;
  FTemp.Size := FTemp.Size + BufferSize;
  FTemp.Position := nPos;
  CopyMemory(FTemp.Memory, Buffer, BufferSize);
  if IsEnd(FTemp, nPos) then
  begin
    if FMode = 2 then
      FStart := GetTickCount;
    if Assigned(FOnEnd) then
      FOnEnd(GetTickCount - FStart);
  end;
  
  if (GetTickCount - FStart) > FDelay then
  begin
    FStartPlay := True;
    FPos := 0;
    FPlayer.Active := True;
  end;
end;

procedure TSpeechRepeat.SetDelay(const Value: Integer);
begin
  FDelay := Value;
end;

procedure TSpeechRepeat.SetMode(const Value: Integer);
begin
  FMode := Value;
end;

procedure TSpeechRepeat.SetOnEnd(const Value: TOnEndEvent);
begin
  FOnEnd := Value;
end;

procedure TSpeechRepeat.Start;
begin
  FRecorder.Active := True;
  if FMode = 1 then
    FStart := GetTickCount;
end;

procedure TSpeechRepeat.Stop;
begin
  FRecorder.Active := False;
  FPlayer.Active := False;
end;

end.
